Deleting a buffer without closing the window
You may use the :split or :vsplit commands to display several windows, with some windows showing different parts of one buffer, while other windows show other buffers. When finished with a buffer, you can close it with the :bdelete command. However, that command will also close all windows currently showing the buffer. The script below defines the :Bclose command that deletes a buffer, while keeping the current window layout (no windows are closed). Usage The :Bclose command deletes a buffer without changing the window layout. For each window where the buffer is currently displayed: *Show the alternate buffer (:buffer #), if any. *Otherwise, show the previous buffer (:bprevious), if any. *Otherwise, show an empty buffer. ;:Bclose :Close buffer in current window. ;:Bclose N'' :Close buffer number ''N (as shown by :ls). ;:Bclose Name :Close buffer named Name (as shown by :ls). Assuming the default backslash leader key, you can also press \bd to close (delete) the buffer in the current window (same as :Bclose). Like the :bdelete command, :Bclose will fail if the buffer has been modified. You can append ! to discard all changes (for example, :Bclose! will delete the buffer in the current window; any changes to the buffer are lost). By default, :Bclose will close a buffer even if it is displayed in multiple windows (the windows are not closed). Put the following in your vimrc if you would prefer that a buffer is not closed if it is displayed more than once: :let bclose_multiple = 0 Script Create file ~/.vim/plugin/bclose.vim (Unix) or $HOME/vimfiles/plugin/bclose.vim (Windows) containing the script below, then restart Vim. " Delete buffer while keeping window layout (don't close buffer's windows). " Version 2008-11-18 from http://vim.wikia.com/wiki/VimTip165 if v:version < 700 || exists('loaded_bclose') || &cp finish endif let loaded_bclose = 1 if !exists('bclose_multiple') let bclose_multiple = 1 endif " Display an error message. function! s:Warn(msg) echohl ErrorMsg echomsg a:msg echohl NONE endfunction " Command ':Bclose' executes ':bd' to delete buffer in current window. " The window will show the alternate buffer (Ctrl-^) if it exists, " or the previous buffer (:bp), or a blank buffer if no previous. " Command ':Bclose!' is the same, but executes ':bd!' (discard changes). " An optional argument can specify which buffer to close (name or number). function! s:Bclose(bang, buffer) if empty(a:buffer) let btarget = bufnr('%') elseif a:buffer =~ '^\d\+$' let btarget = bufnr(str2nr(a:buffer)) else let btarget = bufnr(a:buffer) endif if btarget < 0 call s:Warn('No matching buffer for '.a:buffer) return endif if empty(a:bang) && getbufvar(btarget, '&modified') call s:Warn('No write since last change for buffer '.btarget.' (use :Bclose!)') return endif " Numbers of windows that view target buffer which we will delete. let wnums = filter(range(1, winnr('$')), 'winbufnr(v:val) btarget') if !g:bclose_multiple && len(wnums) > 1 call s:Warn('Buffer is in multiple windows (use ":let bclose_multiple=1")') return endif let wcurrent = winnr() for w in wnums execute w.'wincmd w' let prevbuf = bufnr('#') if prevbuf > 0 && buflisted(prevbuf) && prevbuf != btarget buffer # else bprevious endif if btarget bufnr('%') " Numbers of listed buffers which are not the target to be deleted. let blisted = filter(range(1, bufnr('$')), 'buflisted(v:val) && v:val != btarget') " Listed, not target, and not displayed. let bhidden = filter(copy(blisted), 'bufwinnr(v:val) < 0') " Take the first buffer, if any (could be more intelligent). let bjump = (bhidden + blisted + -1)0 if bjump > 0 execute 'buffer '.bjump else execute 'enew'.a:bang endif endif endfor execute 'bdelete'.a:bang.' '.btarget execute wcurrent.'wincmd w' endfunction command! -bang -complete=buffer -nargs=? Bclose call Bclose(, ) nnoremap bd :Bclose Alternative Script Below, I have a new, more complicated version of above script. The below script will actually create a scratch buffer if there are no listed buffers left. The script, in addition, takes care of a small annoyance. Before, if you 1) open vim, 2) :e a file, 3) :bd, 4) :e the same file, then there will be two buffers listed (that file and a name buffer). The following script ensures this doesn't happen. Everything in this tutorial assumes the user does "set hidden". Using this Kwbd command (:Kwbd) will make Vim windows behave more like an IDE, or maybe even better. You can also setup a mapping, see the end of the script. "here is a more exotic version of my original Kwbd script "delete the buffer; keep windows; create a scratch buffer if no buffers left function s:Kwbd(kwbdStage) if(a:kwbdStage 1) if(&modified) let answer = confirm("This buffer has been modified. Are you sure you want to delete it?", "&Yes\n&No", 2) if(answer != 1) return endif endif if(!buflisted(winbufnr(0))) bd! return endif let s:kwbdBufNum = bufnr("%") let s:kwbdWinNum = winnr() windo call s:Kwbd(2) execute s:kwbdWinNum . 'wincmd w' let s:buflistedLeft = 0 let s:bufFinalJump = 0 let l:nBufs = bufnr("$") let l:i = 1 while(l:i <= l:nBufs) if(l:i != s:kwbdBufNum) if(buflisted(l:i)) let s:buflistedLeft = s:buflistedLeft + 1 else if(bufexists(l:i) && !strlen(bufname(l:i)) && !s:bufFinalJump) let s:bufFinalJump = l:i endif endif endif let l:i = l:i + 1 endwhile if(!s:buflistedLeft) if(s:bufFinalJump) windo if(buflisted(winbufnr(0))) | execute "b! " . s:bufFinalJump | endif else enew let l:newBuf = bufnr("%") windo if(buflisted(winbufnr(0))) | execute "b! " . l:newBuf | endif endif execute s:kwbdWinNum . 'wincmd w' endif if(buflisted(s:kwbdBufNum) || s:kwbdBufNum bufnr("%")) execute "bd! " . s:kwbdBufNum endif if(!s:buflistedLeft) set buflisted set bufhidden=delete set buftype= setlocal noswapfile endif else if(bufnr("%") s:kwbdBufNum) let prevbufvar = bufnr("#") if(prevbufvar > 0 && buflisted(prevbufvar) && prevbufvar != s:kwbdBufNum) b # else bn endif endif endif endfunction command! Kwbd call s:Kwbd(1) nnoremap Kwbd :Kwbd " Create a mapping (e.g. in your .vimrc) like this: "nmap ! Kwbd See also * Bbye Delete buffers and close files in Vim without messing up your window layout. Rewritten Bclose.vim to handle multiple windows. Comes with warranty! * not useful because it doesn't work as expected (if you close a buffer that's open in several windows, those windows close) * unload/delete/wipe a buffer, keep its window(s), display last accessed buffer(s) * provides this capability with a simple user interface Comments For getting asked what should be done, when a file has been modified I use normally :confirm :bd. So I changed the script in 2lines to achieve this: if empty(a:bang) && getbufvar(btarget, '&modified') call s:Warn('No write since last change for buffer '.btarget.' (use :Bclose!)') " return endif ... endif endfor " execute 'bdelete'.a:bang.' '.btarget execute ':confirm :bdelete '.btarget execute wcurrent.'wincmd w' Just comment out the return and replace the command. greetings - Joe